package com.shelpe.services.sinbad.service.impl;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.shelpe.services.sinbad.model.Keyword;
import com.shelpe.services.sinbad.model.KeywordExample;
import com.shelpe.services.sinbad.model.RptKeyword;
import com.shelpe.services.sinbad.model.RptKeywordExample;
import com.shelpe.services.sinbad.model.RptKeywordExample.Criteria;
import com.shelpe.services.sinbad.model.RptKeywordParam;
import com.shelpe.services.sinbad.readdao.KeywordMapper;
import com.shelpe.services.sinbad.readdao.ReadRptKeywordMapper;
import com.shelpe.services.sinbad.service.RptKeywordService;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class RptKeywordServiceImpl implements RptKeywordService {

	private static SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd");

	@Autowired
	private ReadRptKeywordMapper rptKeywordMapper;
	@Autowired
	private KeywordMapper keywordMapper;

	@Override
	public List<KeywordCompositeID> getKeywordIds(RptKeywordParam param) {
		log.debug("getKeywordIds param:{}", param.toString());
		long start = System.currentTimeMillis();
		Set<Long> keywordIds = new HashSet<Long>(); // 用来存放已经加过的keywordid，
													// 但是这里有个小bug。进行过滤的时候，没有set里面去掉
		List<KeywordCompositeID> ids = new ArrayList<KeywordCompositeID>();
		if (param.getImpressionsDay() > 0) {
			// 根据展现量查询
			param.setDay(param.getImpressionsDay());
			List<RptKeyword> words = rptKeywordMapper.selectImpressionsByExample(paramToExample(param));
			List<KeywordCompositeID> incIDs = new ArrayList<KeywordCompositeID>();
			for (RptKeyword rpt : words) {
				if (rpt.getImpressions() == 0) {
					if (keywordIds.add(rpt.getKeywordId())) {
						incIDs.add(new KeywordCompositeID(rpt.getKeywordId(), rpt.getCampaignId(), 0));
					}
				}
			}
			incIDs = this.filterByCost(param.getUserId(), incIDs);
			ids.addAll(incIDs);
			log.info("select by impression cost {} ms", System.currentTimeMillis() - start, param);
			start = System.currentTimeMillis();
		}
		if (param.getClickDay() > 0) {
			// 根据点击量查询
			param.setDay(param.getClickDay());
			List<RptKeyword> words = rptKeywordMapper.selectClickByExample(paramToExample(param));

			List<KeywordCompositeID> incIDs = new ArrayList<KeywordCompositeID>();
			for (RptKeyword rpt : words) { // 展现量大于1000并且点击量小于1
				if (rpt.getImpressions() > 1000 && rpt.getClick() < 1) {
					if (keywordIds.add(rpt.getKeywordId())) {
						incIDs.add(new KeywordCompositeID(rpt.getKeywordId(), rpt.getCampaignId(), 0));
					}
				}
			}
			incIDs = this.filterByCost(param.getUserId(), incIDs);
			ids.addAll(incIDs);
			log.info("select by click cost {} ms", System.currentTimeMillis() - start, param);
			start = System.currentTimeMillis();
		}
		if (param.getMobileQscore() > 0) {
			KeywordExample ke = new KeywordExample();
			ke.setUserId(param.getUserId());
			KeywordExample.Criteria criteria = ke.createCriteria();
			criteria.andWirelessQscoreLessThanOrEqualTo((float) param.getMobileQscore())
					.andWirelessQscoreGreaterThan(0f);
			if (param.getAdgroupId() != null) {
				criteria.andAdgroupIdEqualTo(param.getAdgroupId());
			}
			if (param.getAdgroupIds() != null) {
				criteria.andAdgroupIdIn(param.getAdgroupIds());
			}
			if (param.getCampaignId() != null) {
				criteria.andCampaignIdEqualTo(param.getCampaignId());
			}
			if (param.getCampaignIds() != null) {
				criteria.andCampaignIdIn(param.getCampaignIds());
			}
			List<Keyword> keywords = this.keywordMapper.selectByExample(ke);
			List<KeywordCompositeID> incIDs = new ArrayList<KeywordCompositeID>();
			for (Keyword kw : keywords) {
				if (keywordIds.add(kw.getKeywordId())) {
					incIDs.add(new KeywordCompositeID(kw.getKeywordId(), kw.getCampaignId(), 0));
				}
			}
			incIDs = this.filterByCost(param.getUserId(), incIDs);
			incIDs = this.filterByQscore(param.getUserId(), incIDs);
			ids.addAll(incIDs);

			log.info("select by qscore cost {} ms", System.currentTimeMillis() - start, param);
			start = System.currentTimeMillis();
		}
		if (param.getQscore() > 0) {
			KeywordExample ke = new KeywordExample();
			ke.setUserId(param.getUserId());
			KeywordExample.Criteria criteria = ke.createCriteria();
			criteria.andQscoreLessThanOrEqualTo((float) param.getQscore()).andQscoreGreaterThan(0f);
			if (param.getAdgroupId() != null) {
				criteria.andAdgroupIdEqualTo(param.getAdgroupId());
			}
			if (param.getAdgroupIds() != null) {
				criteria.andAdgroupIdIn(param.getAdgroupIds());
			}
			if (param.getCampaignId() != null) {
				criteria.andCampaignIdEqualTo(param.getCampaignId());
			}
			if (param.getCampaignIds() != null) {
				criteria.andCampaignIdIn(param.getCampaignIds());
			}
			List<Keyword> keywords = this.keywordMapper.selectByExample(ke);
			List<KeywordCompositeID> incIDs = new ArrayList<KeywordCompositeID>();
			for (Keyword kw : keywords) {
				if (keywordIds.add(kw.getKeywordId())) {
					incIDs.add(new KeywordCompositeID(kw.getKeywordId(), kw.getCampaignId(), 0));
				}
			}
			incIDs = this.filterByCost(param.getUserId(), incIDs);
			incIDs = this.filterByWirelessQscore(param.getUserId(), incIDs);
			ids.addAll(incIDs);

			log.info("select by qscore cost {} ms", System.currentTimeMillis() - start, param);
			start = System.currentTimeMillis();
		}

		return ids;
	}

	private List<KeywordCompositeID> filterByWirelessQscore(long userID, List<KeywordCompositeID> ids) {
		List<Long> foundKeywordIDs = new ArrayList<Long>();
		for (KeywordCompositeID id : ids) {
			foundKeywordIDs.add(id.getKeywordID());
		}

		if (foundKeywordIDs.size() > 0) {
			KeywordExample ke = new KeywordExample();
			ke.setUserId(userID);
			ke.createCriteria().andWirelessQscoreBetween(1, 6).andKeywordIdIn(foundKeywordIDs);
			List<Keyword> keywords = this.keywordMapper.selectByExample(ke);
			List<KeywordCompositeID> foundIDs = new ArrayList<KeywordCompositeID>();
			for (Keyword kw : keywords) {
				KeywordCompositeID id = this.filterByKeywordID(ids, kw.getKeywordId());
				if (id != null) {
					foundIDs.add(id);
				}
			}
			ids = foundIDs;
		}
		return ids;
	}

	private List<KeywordCompositeID> filterByQscore(long userID, List<KeywordCompositeID> ids) {
		List<Long> foundKeywordIDs = new ArrayList<Long>();
		for (KeywordCompositeID id : ids) {
			foundKeywordIDs.add(id.getKeywordID());
		}

		if (foundKeywordIDs.size() > 0) {
			KeywordExample ke = new KeywordExample();
			ke.setUserId(userID);
			ke.createCriteria().andQscoreBetween(1, 6).andKeywordIdIn(foundKeywordIDs);
			List<Keyword> keywords = this.keywordMapper.selectByExample(ke);
			List<KeywordCompositeID> foundIDs = new ArrayList<KeywordCompositeID>();
			for (Keyword kw : keywords) {
				KeywordCompositeID id = this.filterByKeywordID(ids, kw.getKeywordId());
				if (id != null) {
					foundIDs.add(id);
				}
			}
			ids = foundIDs;
		}
		return ids;
	}

	private List<KeywordCompositeID> filterByCost(long userID, List<KeywordCompositeID> ids) {
		List<Long> foundKeywordIDs = new ArrayList<Long>();
		for (KeywordCompositeID id : ids) {
			foundKeywordIDs.add(id.getKeywordID());
		}

		// 这里查询30天内的每条关键词
		if (foundKeywordIDs.size() > 0) {
			RptKeywordExample ex = new RptKeywordExample();
			ex.setUserId(userID);
			RptKeywordExample.Criteria cre = ex.createCriteria();
			cre.andKeywordIdIn(foundKeywordIDs);
			cre.andDateGreaterThanOrEqualTo(DateUtils.addDays(DateUtils.truncate(new Date(), Calendar.DATE), -30));
			// 进行函数 sum 的操作，获取每个关键词的总和
			List<RptKeyword> rpts = this.rptKeywordMapper.selectSummariesMetricByKeyword(ex);
			// 对每个可能被删除的关键词进行过滤，避免误删。
			for (RptKeyword rpt : rpts) {
				KeywordCompositeID id = this.filterByKeywordID(ids, rpt.getKeywordId());
				if (id != null && rpt.getCost() > 0) {
					ids.remove(id);
				}
			}
		}
		return ids;
	}

	private KeywordCompositeID filterByKeywordID(List<KeywordCompositeID> ids, long keywordID) {
		for (KeywordCompositeID id : ids) {
			if (id.getKeywordID() == keywordID) {
				return id;
			}
		}
		return null;
	}

	@Override
	public RptKeyword getSummariesMetric(RptKeywordParam param) {
		log.debug("getSummariesMetric param:{}", param.toString());
		return rptKeywordMapper.selectSummariesMetric(paramToExample(param));
	}

	@Override
	public List<RptKeyword> getReportsTrend(RptKeywordParam param) {
		log.info("getReportsTrend param:{}", param.toString());
		List<RptKeyword> retList = null;
		if (param.getAdgroupId() != null) {// 以关键词分组
			log.info("getReportsTrend group by keyword");
			retList = rptKeywordMapper.selectReportsTrendByAdgroupId(paramToExample(param));
		} else if (param.getCampaignId() != null
				|| (param.getAdgroupIds() != null && param.getAdgroupIds().size() > 0)) {// 以推广组分组
			log.info("getReportsTrend group by adgroupId");
			retList = rptKeywordMapper.selectReportsTrendByCampaignId(paramToExample(param));
		} else {
			log.info("getReportsTrend  group by campaignId");
			retList = rptKeywordMapper.selectReportsTrendByUserId(paramToExample(param));
		}
		return retList;
	}

	@Override
	public List<RptKeyword> getReportsTrendByDate(RptKeywordParam param) {
		log.info("getReportsTrendByDate param:{}", param.toString());
		List<RptKeyword> retList = null;
		retList = rptKeywordMapper.selectReportsTrendByDate(paramToExample(param));
		return retList;
	}
	
	@Override
	public List<RptKeyword> getReportsByExample(RptKeywordParam param) {
		log.info("getReportsTrendByDate param:{}", param.toString());
		List<RptKeyword> retList = null;
		retList = rptKeywordMapper.selectByExample(paramToExample(param));
		return retList;
	}

	/**
	 * 对参数进行组装
	 * 
	 * @param param
	 * @return
	 */
	private RptKeywordExample paramToExample(RptKeywordParam param) {
		RptKeywordExample example = new RptKeywordExample();
		example.setUserId(param.getUserId());
		Date date = getDate(0 - param.getDay()); // 前面多少天的数据
		Criteria criteria = example.createCriteria();

		// 如果有起始时间参数，则设置起始时间example; 否则，就是前面多少天的数据
		if (!(param.getStartDate() == null || param.getEndDate() == null)) {
			try {
				criteria.andDateBetween(SDF.parse(param.getStartDate()), SDF.parse(param.getEndDate()));
			} catch (ParseException e) {
				log.error("RptKeywordExample paramToExample date parse:{}", e.getMessage());
			}
		} else {
			criteria.andDateGreaterThanOrEqualTo(date);
		}

		if (param.getKeywordId() != null) {
			criteria.andKeywordIdEqualTo(param.getKeywordId());
		}

		if (param.getKeywordIds() != null) {
			criteria.andKeywordIdIn(param.getKeywordIds());
		}

		if (param.getAdgroupId() != null) {
			criteria.andAdgroupIdEqualTo(param.getAdgroupId());
		}

		if (param.getCampaignId() != null) {
			criteria.andCampaignIdEqualTo(param.getCampaignId());
		}

		if (param.getCampaignIds() != null) {
			criteria.andCampaignIdIn(param.getCampaignIds());
		}

		if (param.getAdgroupIds() != null) {
			criteria.andAdgroupIdIn(param.getAdgroupIds());
		}

		if (param.getSource() != null) {
			switch (param.getSource()) {
			case 0:// all
				criteria.andSourceBetween((byte) 1, (byte) 5);
				break;
			case 1:// mobile
				criteria.andSourceBetween((byte) 4, (byte) 5);
				break;
			case 2:// pc
				criteria.andSourceBetween((byte) 1, (byte) 2);
				break;
			case 3:// 获取质量得分
				criteria.andSourceEqualTo((byte) 23);
				break;
			}
		}
		return example;
	}

	private Date getDate(int amount) {
		return getDate(new Date(), amount);
	}

	private Date getDate(Date date, int amount) {
		Calendar calendar = Calendar.getInstance();
		if (date != null) {
			calendar.setTime(date);
		}
		calendar.add(Calendar.DAY_OF_MONTH, amount);
		return calendar.getTime();
	}

	@Override
	public RptKeyword selectSum(RptKeywordParam param) {
		return rptKeywordMapper.selectSumByExample(paramToExample(param));
	}

	@Override
	public RptKeyword getCampaignSummariesMetric(RptKeywordParam param) {
		log.debug("getSummariesMetric param:{}", param.toString());
		return rptKeywordMapper.selectCampaignSummariesMetric(paramToExample(param));
	}

	@Override
	public Integer countCurrdaySysScore(RptKeywordParam param) {
		// TODO Auto-generated method stub
		return rptKeywordMapper.countCurrdaySysScore(paramToExample(param));
	}

	@Override
	public RptKeyword getCampaignSummariesMetricNew(long userID, long campaignID, String from, String to,
			String sources) {
		return rptKeywordMapper.selectCampaignSummariesMetricNew(userID, campaignID, from, to, sources);
	}

}
